home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Resources / Audio, Video & Photo / Songbird 0.7.0 / Songbird_0.7.0_windows-i686-msvc8.exe / components / sbCommandLine.js < prev    next >
Text File  |  2008-08-06  |  15KB  |  449 lines

  1. /**
  2. //
  3. // BEGIN SONGBIRD GPL
  4. //
  5. // This file is part of the Songbird web player.
  6. //
  7. // Copyright(c) 2005-2008 POTI, Inc.
  8. // http://songbirdnest.com
  9. //
  10. // This file may be licensed under the terms of of the
  11. // GNU General Public License Version 2 (the "GPL").
  12. //
  13. // Software distributed under the License is distributed
  14. // on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
  15. // express or implied. See the GPL for the specific language
  16. // governing rights and limitations.
  17. //
  18. // You should have received a copy of the GPL along with this
  19. // program. If not, go to http://www.gnu.org/licenses/gpl.html
  20. // or write to the Free Software Foundation, Inc.,
  21. // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  22. //
  23. // END SONGBIRD GPL
  24. //
  25.  */
  26.  
  27. /**
  28.  * \file sbCommandLine.js
  29.  * \brief Implementation of the interface nsICommandLine
  30.  * \todo Implement the -play functionality
  31.  */
  32.  
  33. const Cc = Components.classes;
  34. const Ci = Components.interfaces;
  35. const Cr = Components.results;
  36.  
  37. const SONGBIRD_CLH_CONTRACTID = "@songbirdnest.com/commandlinehandler/general-startup;1?type=songbird";
  38. const SONGBIRD_CLH_CID = Components.ID("{128badd1-aa05-4508-87cc-f3cb3e9b5499}");
  39. const SONGBIRD_CLH_CLASSNAME = "Songbird Command Line Handler";
  40. // "m" for ordinary priority see sbICommandLineHandler.idl
  41. const SONGBIRD_CLH_CATEGORY= "m-songbird-clh";
  42.  
  43. function resolveURIInternal(aCmdLine, aArgument) {
  44.   var uri = aCmdLine.resolveURI(aArgument);
  45.  
  46.   if (!(uri instanceof Components.interfaces.nsIFileURL)) {
  47.     return uri;
  48.   }
  49.  
  50.   return checkUri(uri, aArgument);
  51. }
  52.  
  53. function checkUri(aURI, aURL) {
  54.   try {
  55.     if (aURI instanceof Components.interfaces.nsIFileURL)
  56.       if (aURI.file.exists())
  57.         return aURI;
  58.   }
  59.   catch (e) {
  60.     Components.utils.reportError(e);
  61.   }
  62.  
  63.   // We have interpreted the argument as a relative file URI, but the file
  64.   // doesn't exist. Try URI fixup heuristics: see bug 290782.
  65.  
  66.   try {
  67.     var urifixup = Components.classes["@mozilla.org/docshell/urifixup;1"]
  68.                               .getService(Ci.nsIURIFixup);
  69.  
  70.     aURI = urifixup.createFixupURI(aURL, 0);
  71.   }
  72.   catch (e) {
  73.     Components.utils.reportError(e);
  74.   }
  75.  
  76.   return aURI;
  77. }
  78.  
  79. function shouldLoadURI(aURI) {
  80.   if (!aURI || aURI == "") return false;
  81.   if (aURI && !aURI.schemeIs("chrome"))
  82.     return true;
  83.  
  84.   dump("*** Preventing external load of chrome URI into browser window (" + aURI.spec + ")\n");
  85.   dump("    Use -chrome <uri> instead\n");
  86.   return false;
  87. }
  88.  
  89. /**
  90.  * /brief Songbird commandline handler
  91.  */
  92. function sbCommandLineHandler() {
  93.   this.itemHandlers = []; // array of handlers
  94.   this.itemUriSpecs = []; // array of uri specs
  95.   this.flagHandlers = []; // array of arrays (handler, flag)
  96.   this.flags = [];        // array of arrays (flag, param)
  97. }
  98.  
  99. sbCommandLineHandler.prototype = {
  100.   // there are specific formatting guidelines for help test, see nsICommandLineHandler
  101.   helpInfo : "  -test [tests]        Run tests on the components listed in the\n" +
  102.              "                       optional comma-separated list of tests.\n" +
  103.              "                       If no tests are passed in ALL tests will be run.\n\n" +
  104.              "  [url|path]           Local path/filename to media items to import and play,\n" +
  105.              "                       or URL to load in the browser.\n\n" +
  106.              "  -register-extensions Registers extensions and then quits.\n\n",
  107.   itemHandlers: null,
  108.   itemUriSpecs: null,
  109.   flagHandlers: null,
  110.   flags: null,
  111.  
  112.   handle : function (cmdLine) {
  113.  
  114.     var urilist = [];
  115.     var oldlength = this.itemUriSpecs.length;
  116.  
  117.     if (cmdLine.handleFlag("register-extensions", false)) {
  118.       throw Components.results.NS_ERROR_ABORT;
  119.     }
  120.  
  121.     try {
  122.       var ar;
  123.       while ((ar = cmdLine.handleFlagWithParam("url", false))) {
  124.         urilist.push(resolveURIInternal(cmdLine, ar));
  125.       }
  126.     }
  127.     catch (e) {
  128.       Components.utils.reportError(e);
  129.     }
  130.  
  131.     var tests = null;
  132.     var emptyParam = false;
  133.     try {
  134.       tests = cmdLine.handleFlagWithParam("test", false);
  135.     }
  136.     catch (e) {
  137.       // cmdLine throws if there is no param for the flag, but we want the
  138.       // parameter to be optional, so catch the exception and let ourselves
  139.       // know that things are okay. The flag existed without a param.
  140.       emptyParam = true;
  141.     }
  142.  
  143.     // if there was a parameter or if we had a flag and no param
  144.     if (tests != null || emptyParam) {
  145.       // we're running tests, make sure we don't open a window
  146.       cmdLine.preventDefault = true;
  147.       var testHarness = Cc["@songbirdnest.com/Songbird/TestHarness;1"].getService(Ci.sbITestHarness);
  148.  
  149.       var exception;
  150.       try {
  151.         testHarness.init(tests);
  152.         testHarness.run();
  153.       }
  154.       catch (e) {
  155.         exception = e;
  156.       }
  157.       
  158.  
  159.       var platformStr = Cc["@mozilla.org/system-info;1"]
  160.                         .getService(Ci.nsIPropertyBag2).getProperty("name");
  161.       
  162.       // If we are on Mac, unfortunately the event-queue slows down to slug
  163.       // speed when there isn't a window open and we are shutting down. Since 
  164.       // there isn't a window being used on these unit tests - the hybrid
  165.       // Cocoa/Gecko event loop takes a long time (over 20 minutes) to kill the
  166.       // 100 or so threads that get spooled up during the test cases.
  167.       
  168.       // Unfortunately, this also happens on Windows :(
  169.  
  170.       // To fix this problem, we will use a nasty little hack. Open up the a
  171.       // plain window that closes itself after a couple of seconds. This fires
  172.       // the application shutdown procedure just as if we had closed the main
  173.       // Songbird window.
  174.       //
  175.       // Yes - I know this sucks, I hate myself a little more for doing this.
  176.       if (platformStr == "Darwin" ||
  177.           platformStr == "Windows_NT") {
  178.         var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"]
  179.                  .getService(Ci.nsIWindowWatcher);
  180.         
  181.         ww.openWindow(null, 
  182.                       "chrome://songbird/content/xul/unitTestShutdownWin.xul", 
  183.                       "shutdownwin", "chrome", null);
  184.       }
  185.       else {
  186.         // Linux can follow this 'standard' shutdown procedure:
  187.         //
  188.         // Fake the sequence of observer notifications for app shutdown. This
  189.         // sequence should match that of canQuitApplication (from
  190.         // globalOverlay.js) and nsAppStartup::Quit (from nsAppStartup.cpp).
  191.         var os = Cc["@mozilla.org/observer-service;1"].
  192.                  getService(Ci.nsIObserverService);
  193.  
  194.         // We don't care if anyone tries to cancel quit...
  195.         var dummyCancelQuit = Cc["@mozilla.org/supports-PRBool;1"].
  196.                               createInstance(Ci.nsISupportsPRBool);
  197.         os.notifyObservers(dummyCancelQuit, "quit-application-requested", null);
  198.  
  199.         os.notifyObservers(null, "quit-application-granted", null);
  200.  
  201.         var appStartup = Cc["@mozilla.org/toolkit/app-startup;1"]
  202.                            .getService(Ci.nsIAppStartup);
  203.         appStartup.quit(Ci.nsIAppStartup.eAttemptQuit);
  204.       }
  205.  
  206.       if (exception) {
  207.         throw Cr.NS_ERROR_ABORT;
  208.       }
  209.     }
  210.  
  211.     // XXX bug 2186
  212.     var count = cmdLine.length;
  213.       for (var i = 0; i < count; ++i) {
  214.         // getArgument sometimes causes an exception for the last parameter, 
  215.         // even tho i is always below cmdLine.length ! This doesn't seem to
  216.         // ever happen when the commandline is starting the app, but seems to
  217.         // always do when the app is already started, and the commandline is
  218.         // received from another instance.
  219.         try {
  220.           var curarg = cmdLine.getArgument(i);
  221.         } catch (e) {
  222.           Components.utils.reportError(e);
  223.           // try next argument. there shouldn't be any, but just in case...
  224.           continue
  225.         }
  226.  
  227.         if (curarg == "") continue;
  228.         if (curarg.match(/^-/)) {
  229.           // Components.utils.reportError("Warning: unrecognized command line flag " + curarg + "\n");
  230.           // To emulate the pre-nsICommandLine behavior, we ignore
  231.           // the argument after an unrecognized flag.
  232.           ++i;
  233.         } else {
  234.           try {
  235.             cmdLine.removeArguments(i, i);
  236.             urilist.push(resolveURIInternal(cmdLine, curarg));
  237.           }
  238.           catch (e) {
  239.             Components.utils.reportError("Error opening URI '" + curarg + "' from the command line: " + e + "\n");
  240.           }
  241.         }
  242.       }
  243.  
  244.     for (var uri in urilist) {
  245.       if (shouldLoadURI(urilist[uri])) {
  246.         this.itemUriSpecs.push(urilist[uri].spec);
  247.       }
  248.     }
  249.  
  250.     if (this.itemUriSpecs.length > oldlength)
  251.       this.dispatchItems();
  252.  
  253.     this.handleRemainingFlags(cmdLine);
  254.     this.dispatchFlags();
  255.   },
  256.  
  257.   handleURL: function(aURL) {
  258.     var ioService = Components.classes["@mozilla.org/network/io-service;1"]
  259.                               .getService(Components.interfaces.nsIIOService);
  260.     var uri = ioService.newURI(aURL, null, null);
  261.     uri = checkUri(uri, aURL);
  262.     if (shouldLoadURI(uri)) {
  263.       this.itemUriSpecs.push(uri.spec);
  264.       this.dispatchItems();
  265.     }
  266.   },
  267.  
  268.   handleRemainingFlags: function(cmdLine) {
  269.     while (cmdLine.length) {
  270.       var curarg = cmdLine.getArgument(0);
  271.       if (curarg.match(/^-/)) {
  272.         var flag = curarg.slice(1);
  273.  
  274.         var param;
  275.  
  276.         var emptyParam = false;
  277.         try {
  278.           param = cmdLine.handleFlagWithParam(flag, false);
  279.         }
  280.         catch (e) {
  281.           // cmdLine throws if there is no param for the flag, but we want the
  282.           // parameter to be optional, so catch the exception and let ourselves
  283.           // know that things are okay. The flag existed without a param.
  284.           emptyParam = true;
  285.           cmdLine.handleFlag(flag, false);
  286.         }
  287.  
  288.         // if there was a parameter or if we had a flag and no param
  289.         if (param != null || emptyParam) {
  290.           // record the flag for handling by flag handlers
  291.           this.flags.push([flag, param]);
  292.         }
  293.       } else {
  294.         // this should really not occur, because the case should have
  295.         // been handled as a play item earlier. however, if for some reason
  296.         // it does occur, not doing the following would cause an infinite loop,
  297.         // so do it just in case.
  298.         cmdLine.removeArguments(0, 0);
  299.       }
  300.     }
  301.   },
  302.  
  303.   addItemHandler: function (aHandler) {
  304.     this.itemHandlers.push(aHandler);
  305.     // dispatch unhandled items immediatly to this handler
  306.     this.dispatchItemsToHandler(aHandler);
  307.   },
  308.  
  309.   removeItemHandler: function(aHandler) {
  310.     var index = this.itemHandlers.indexOf(aHandler);
  311.     if (index != -1) this.itemHandlers.splice(index, 1);
  312.   },
  313.  
  314.   dispatchItemsToHandler: function(aHandler) {
  315.     var count = 0;
  316.     var total = this.itemUriSpecs.length;
  317.     for (var i=0; i < this.itemUriSpecs.length; i++) {
  318.       if (aHandler.handleItem(this.itemUriSpecs[i], count++, total)) {
  319.         this.itemUriSpecs.splice(i--, 1);
  320.       }
  321.     }
  322.   },
  323.  
  324.   dispatchItems: function() {
  325.     // The last handler to get registered gets
  326.     // priority over the first ones, so that if
  327.     // there are several instances of the main window,
  328.     // the items open in the one created last.
  329.     for (var handleridx = this.itemHandlers.length-1; handleridx >= 0; handleridx--) {
  330.       this.dispatchItemsToHandler(this.itemHandlers[handleridx]);
  331.       if (this.itemUriSpecs.length == 0) break;
  332.     }
  333.   },
  334.  
  335.   addFlagHandler: function (aHandler, aFlag) {
  336.     var entry = [aHandler, aFlag];
  337.     this.flagHandlers.push(entry);
  338.     // dispatch unhandled flags immediatly to this handler
  339.     this.dispatchFlagsToHandler(entry);
  340.   },
  341.  
  342.   removeFlagHandler: function(aHandler, aFlag) {
  343.     for (var i=this.flagHandlers.length-1;i>=0;i--) {
  344.       var entry = this.flagHandlers[i];
  345.       if (entry[0] == aHandler && entry[1] == aFlag) {
  346.         this.flagHandlers.splice(i, 1);
  347.         return;
  348.       }
  349.     }
  350.   },
  351.  
  352.   dispatchFlagsToHandler: function(aHandlerEntry) {
  353.     var handler = aHandlerEntry[0];
  354.     var flag = aHandlerEntry[1];
  355.     for (var i=0; i < this.flags.length; i++) {
  356.       if (this.flags[i][0] == flag) {
  357.         if (handler.handleFlag(this.flags[i][0], this.flags[i][1])) {
  358.           this.flags.splice(i--, 1);
  359.         }
  360.       }
  361.     }
  362.   },
  363.  
  364.   dispatchFlags: function() {
  365.     // The last handler to get registered gets
  366.     // priority over the first ones, so that if
  367.     // there are several instances of the main window,
  368.     // the flags are handled by the one created last.
  369.     for (var handleridx = this.flagHandlers.length-1; handleridx >= 0; handleridx--) {
  370.       this.dispatchFlagsToHandler(this.flagHandlers[handleridx]);
  371.       if (this.flags.length == 0) break;
  372.     }
  373.   },
  374.  
  375.   QueryInterface : function clh_QI(iid) {
  376.     if (iid.equals(Ci.nsICommandLineHandler) ||
  377.         iid.equals(Ci.sbICommandLineManager) ||
  378.         iid.equals(Ci.nsISupports))
  379.       return this;
  380.  
  381.     throw Cr.NS_ERROR_NO_INTERFACE;
  382.   }
  383. }; // sbCommandeLineHandler
  384.  
  385. /**
  386.  * /brief The module for getting the commandline handler
  387.  */
  388. const sbCommandLineHandlerModule = {
  389.   registerSelf : function (compMgr, fileSpec, location, type) {
  390.     compMgr.QueryInterface(Ci.nsIComponentRegistrar);
  391.     compMgr.registerFactoryLocation(SONGBIRD_CLH_CID,
  392.                                     SONGBIRD_CLH_CLASSNAME,
  393.                                     SONGBIRD_CLH_CONTRACTID,
  394.                                     fileSpec,
  395.                                     location,
  396.                                     type);
  397.  
  398.     var catMan = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
  399.     catMan.addCategoryEntry("command-line-handler",
  400.                             SONGBIRD_CLH_CATEGORY,
  401.                             SONGBIRD_CLH_CONTRACTID,
  402.                             true,
  403.                             true);
  404.   },
  405.  
  406.   getClassObject : function (compMgr, cid, iid) {
  407.     if (!cid.equals(SONGBIRD_CLH_CID))
  408.       throw Cr.NS_ERROR_NO_INTERFACE;
  409.  
  410.     if (!iid.equals(Ci.nsIFactory))
  411.       throw Cr.NS_ERROR_NOT_IMPLEMENTED;
  412.  
  413.     return this.mFactory;
  414.   },
  415.  
  416.   mFactory : {
  417.     createInstance : function (outer, iid) {
  418.       if (outer != null)
  419.         throw Cr.NS_ERROR_NO_AGGREGATION;
  420.       return (new sbCommandLineHandler()).QueryInterface(iid);
  421.     }
  422.   },
  423.  
  424.   unregisterSelf : function (compMgr, location, type) {
  425.     compMgr.QueryInterface(Ci.nsIComponentRegistrar);
  426.     compMgr.unregisterFactoryLocation(SONGBIRD_CLH_CID, location);
  427.  
  428.     var catMan = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
  429.     catMan.deleteCategoryEntry("command-line-handler", SONGBIRD_CLH_CATEGORY);
  430.   },
  431.  
  432.   canUnload : function (compMgr) {
  433.     return true;
  434.   },
  435.  
  436.   QueryInterface : function (iid) {
  437.     if ( !iid.equals(Ci.nsIModule) ||
  438.          !iid.equals(Ci.nsISupports) )
  439.       throw Cr.NS_ERROR_NO_INTERFACE;
  440.     return this;
  441.   }
  442.  
  443. }; // sbCommandLineHandlerModule
  444.  
  445. function NSGetModule(comMgr, fileSpec)
  446. {
  447.   return sbCommandLineHandlerModule;
  448. }
  449.